﻿// Copyright (c) 2009 Daniel Grunwald
// 
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
// 
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

using System;
using System.Collections.Generic;
using System.IO;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Threading;
using System.Xml;

using ICSharpCode.AvalonEdit.CodeCompletion;
using ICSharpCode.AvalonEdit.Folding;
using ICSharpCode.AvalonEdit.Highlighting;
using Microsoft.Win32;

using n_ControlCenter;
using n_ControlCenter.n_CThread;
using n_CCode;
using n_ET;

using n_Compiler;
using n_CharType;

using n_StructList;
using n_UnitList;
using n_VarList;
using n_VarType;
using n_VdataList;
using n_FunctionList;

namespace AvalonEdit.Sample
{
	/// <summary>
	/// Interaction logic for Window1.xaml
	/// </summary>
	public partial class Window1 : Window
	{
		public Window1()
		{
			// Load our custom highlighting definition
			IHighlightingDefinition customHighlighting;
			using (Stream s = typeof(Window1).Assembly.GetManifestResourceStream("AvalonEdit.Sample.CustomHighlighting.xshd")) {
				if (s == null)
					throw new InvalidOperationException("Could not find embedded resource");
				using (XmlReader reader = new XmlTextReader(s)) {
					customHighlighting = ICSharpCode.AvalonEdit.Highlighting.Xshd.
						HighlightingLoader.Load(reader, HighlightingManager.Instance);
				}
			}
			// and register it in the HighlightingManager
			HighlightingManager.Instance.RegisterHighlighting("Custom Highlighting", new string[] { ".cool" }, customHighlighting);
			
			InitializeComponent();
			
			//设置需要高亮的集合
			//textEditor.SyntaxHighlighting = HighlightingManager.Instance.GetDefinition("C#");
			textEditor.SyntaxHighlighting = customHighlighting;
			
			//自定义视图也带有代码折叠
			foldingStrategy = new BraceFoldingStrategy();
			foldingManager = FoldingManager.Install(textEditor.TextArea);
			UpdateFoldings();
			
			textEditor.TextArea.TextEntering += textEditor_TextArea_TextEntering;
			textEditor.TextArea.TextEntered += textEditor_TextArea_TextEntered;
			textEditor.TextChanged += textEditor_TextArea_TextChanged;
			
			textEditor.MouseEnter += textEditor_MouseEnter;
			
			textEditor.KeyDown += textEditor_KeyDown;
			textEditor.KeyUp += textEditor_KeyUp;
			textEditor.ShowLineNumbers = true;
			
			CurrentFileName = null;
			
			MessageInit();
			
			DispatcherTimer foldingUpdateTimer = new DispatcherTimer();
			foldingUpdateTimer.Interval = TimeSpan.FromSeconds(2);
			foldingUpdateTimer.Tick += delegate { UpdateFoldings(); };
			foldingUpdateTimer.Start();
			
			this.Closing += WindowsClosing;
		}
		
		readonly FoldingManager foldingManager;
		readonly BraceFoldingStrategy foldingStrategy;
		
		void UpdateFoldings()
		{
			foldingStrategy.UpdateFoldings(foldingManager, textEditor.Document);
		}
		
		//===============================================================
		bool v_isChanged;
		bool isChanged {
			get {
				return v_isChanged;
			}
			set {
				v_isChanged = value;
			}
		}
		
		string v_CurrentFileName;
		string CurrentFileName {
			get {
				return v_CurrentFileName;
			}
			set {
				v_CurrentFileName = value;
				
			}
		}
		
		//刷新标题栏
		void RefreshTitle()
		{
			if( v_CurrentFileName != null ) {
				string FileName = v_CurrentFileName.Remove( 0, v_CurrentFileName.LastIndexOf( "\\" ) + 1 );
				if( isChanged ) {
					FileName += "*";
				}
				this.Title = "linkboy for Arduino - " + FileName + " (" + v_CurrentFileName + ")";
			}
			else {
				this.Title = "linkboy for Arduino - (文件尚未保存)";
			}
		}
		
		void openFileClick(object sender, RoutedEventArgs e)
		{
			if( isChanged ) {
				MessageBoxResult mr = MessageBox.Show( "文件已经被修改, 需要保存吗?", "文件保存提示", MessageBoxButton.YesNoCancel );
				if( mr == MessageBoxResult.Cancel ) {
					return;
				}
				if( mr == MessageBoxResult.Yes ) {
					if( !SaveFile() ) {
						return;
					}
				}
				if( mr == MessageBoxResult.No ) {
					//...
				}
			}
			OpenFileDialog dlg = new OpenFileDialog();
			dlg.CheckFileExists = true;
			if (dlg.ShowDialog() ?? false) {
				CurrentFileName = dlg.FileName;
				textEditor.Load( CurrentFileName );
				isChanged = false;
				RefreshTitle();
			}
		}
		
		void saveFileClick(object sender, EventArgs e)
		{
			bool b = SaveFile();
		}
		
		//保存完成返回 true
		bool SaveFile()
		{
			if (CurrentFileName == null) {
				SaveFileDialog dlg = new SaveFileDialog();
				dlg.DefaultExt = ".txt";
				if (dlg.ShowDialog() ?? false) {
					CurrentFileName = dlg.FileName;
				} else {
					return false;
				}
			}
			textEditor.Save(CurrentFileName);
			isChanged = false;
			RefreshTitle();
			return true;
		}
		
		//===============================================================
		
		bool isControlPress = false;
		bool isLeftShiftPress = false;
		
		void textEditor_KeyUp(object sender, KeyEventArgs e)
		{
			isControlPress = false;
			isLeftShiftPress = false;
		}
		
		void textEditor_KeyDown(object sender, KeyEventArgs e)
		{
			if( isControlPress && e.Key == Key.S ) {
				SaveFile();
				e.Handled = true;
				return;
			}
			if( e.Key == Key.LeftCtrl || e.Key == Key.RightCtrl ) {
				isControlPress = true;
				return;
			}
			if( e.Key == Key.LeftShift || e.Key == Key.RightShift ) {
				isLeftShiftPress = true;
				return;
			}
			//==========================================================
			if( isLeftShiftPress && e.Key == Key.OemPlus ) {
				try {
					e.Handled = AddSplit( 50, '+' );
				}
				catch {
					//n_OS.VIO.Show( ee.ToString() );
				}
				return;
			}
			if( !isLeftShiftPress && e.Key == Key.OemMinus ) {
				try {
					e.Handled = AddSplit( 50, '-' );
				}
				catch {
					//n_OS.VIO.Show( ee.ToString() );
				}
				return;
			}
			if( isLeftShiftPress && e.Key == Key.D8 ) {
				try {
					e.Handled = AddSplit( 50, '*' );
				}
				catch {
					//n_OS.VIO.Show( ee.ToString() );
				}
				return;
			}
			if( !isLeftShiftPress && e.Key == Key.OemQuestion ) {
				try {
					e.Handled = AddSplit( 50, '/' );
				}
				catch {
					//n_OS.VIO.Show( ee.ToString() );
				}
				return;
			}
			if( !isLeftShiftPress && e.Key == Key.OemPlus ) {
				try {
					e.Handled = AddSplit( 70, '=' );
				}
				catch {
					//n_OS.VIO.Show( ee.ToString() );
				}
				return;
			}
			//==========================================================
			
			if( isLeftShiftPress && e.Key == Key.OemOpenBrackets ) {
				try {
					SwitchReturnButton();
				}
				catch {
					//n_OS.VIO.Show( ee.ToString() );
				}
				e.Handled = true;
			}
		}
		
		//添加分割符
		bool AddSplit( int SLength, char c )
		{
			int CurrentIndex = textEditor.SelectionStart - 1;//当前的序号
			int CLength = 0;
			while( CurrentIndex >= 0 ) {
				if( textEditor.Text[CurrentIndex] == '\n' ) {
					break;
				}
				CLength++;
				CurrentIndex--;
			}
			int S1 = CurrentIndex + 1;
			string Line1 = textEditor.Text.Substring( S1, CLength );
			
			if( Line1.TrimStart( '\t' ) !=  "//" ) {
				return false;
			}
			
			int n;
			for( n = 0; n < Line1.Length; ++n ) {
				if( Line1[ n ] != '\t' ) {
					break;
				}
			}
			string BN = new string( c, SLength );
			//string BNC = new string( '\t', n );
			textEditor.SelectedText = BN;// + "\n" + BNC;
			textEditor.SelectionLength = 0;
			textEditor.SelectionStart += SLength;//1 + n + SLength;
			
			return true;
		}
		
		//设置回车等效字符串
		void SwitchReturnButton()
		{
			int CurrentIndex = textEditor.SelectionStart - 1;//当前的序号
			int CLength = 0;
			while( CurrentIndex >= 0 ) {
				if( textEditor.Text[CurrentIndex] == '\n' ) {
					break;
				}
				CLength++;
				CurrentIndex--;
			}
			int S1 = CurrentIndex + 1;
			string Line1 = textEditor.Text.Substring( S1, CLength );
			
			int n;
			for( n = 0; n < Line1.Length; ++n ) {
				if( Line1[ n ] != '\t' ) {
					break;
				}
			}
			string BN = new string( '\t', n + 1 );
			string BNC = new string( '\t', n );
			textEditor.SelectedText = "{\n" + BN + "\n" + BNC + "}";
			textEditor.SelectionLength = 0;
			textEditor.SelectionStart += 3 + n;
		}
		
		//===============================================================
		
		CompletionWindow completionWindow;
		
		void textEditor_TextArea_TextChanged(object sender, EventArgs e)
		{
			isChanged = true;
			RefreshTitle();
		}
		
		void textEditor_TextArea_TextEntered(object sender, TextCompositionEventArgs e)
		{
			if (e.Text == ".") {
				AddList();
			}
		}
		
		void textEditor_TextArea_TextEntering(object sender, TextCompositionEventArgs e)
		{
			if (e.Text.Length > 0 && completionWindow != null) {
				if (!char.IsLetterOrDigit(e.Text[0])) {
					// Whenever a non-letter is typed while the completion window is open,
					// insert the currently selected element.
					completionWindow.CompletionList.RequestInsertion(e);
				}
			}
			// do not set e.Handled=true - we still want to insert the character that was typed
		}
		
		void textEditor_MouseEnter(object sender, EventArgs e)
		{
			HiddError();
		}
		
		void ToolBoxClick(object sender, EventArgs e)
		{
			T.T.ToolBox.Run();
		}
		
		//添加列表
		void AddList()
		{
			//if( ControlCenter.isBusy() ) {
			//	return;
			//}
			string UnitName = "";
			for( int i = textEditor.SelectionStart - 2; i >= 0; --i ) {
				char c = textEditor.Text[ i ];
				
				if( !CharType.isLetterOrNumber( c ) && c != '#' ) {
					break;
				}
				UnitName = c + UnitName;
			}
			if( UnitName == ""  ) {
				return;
			}
			string FullUnitName = (UnitName == VarType.Root)? VarType.Root: VarType.Root + "." + UnitName;
			
			int UnitIndex = UnitList.GetIndex( FullUnitName);
			if( UnitIndex == -1 ) {
				//return;
			}
			
			string NameSet = null;
			NameSet += FunctionList.GetFunctionNames( FullUnitName );
			NameSet += VarList.GetVarNames( FullUnitName );
			NameSet += StructList.GetStructNames( FullUnitName );
			NameSet += VdataList.GetVdataNames( FullUnitName );
			NameSet += UnitList.GetUnitNames( FullUnitName );
			if( NameSet == null || NameSet == "" ) {
				return;
			}
			// open code completion after the user has pressed dot:
			completionWindow = new CompletionWindow(textEditor.TextArea);
			// provide AvalonEdit with the data:
			IList<ICompletionData> data = completionWindow.CompletionList.CompletionData;
			
			string[] Set = NameSet.TrimEnd( ';' ).Split( ';' );
			for( int j = 0; j < Set.Length; ++j ) {
				data.Add( new MyCompletionData( Set[ j ] ) );
			}
			completionWindow.Show();
			completionWindow.Closed += delegate {
				completionWindow = null;
			};
		}
		
		//===============================================================
		
		RichTextBox rt0;
		ListBox listBox;
		
		void MessageInit()
		{
			//初始化
			string DefaultFilePath = A.Init( null );
			
			T.T.ControlInit();
			
			ControlCenter.D_StartCompile = Start;
			CThread.D_ShowError = ShowError;
			CThread.D_HiddError = HiddError;
			
			Compiler.CompilingStep += AddCompileMessage;
			Compiler.CheckStep += AddCheckMessage;
			
			ISP.ISPStep = ShowISPStep;
			ISP.ProgressStep = ShowProgressStep;
			
			rt0 = new RichTextBox();
			listBox = new ListBox();
			listBox.SelectionChanged += ErrorList_SelectionChanged;
			
			TabItem ti0 = new TabItem();
			ti0.Header = "输出";
			//ti0.Content = rt0;
			ti0.Content = listBox;
			
			tabControl.Items.Add( ti0 );
			
			tabControl.MouseLeftButtonDown += ti0_MouseDown;
			
			TabItem ti1 = new TabItem();
			ti1.Header = "错误";
			//tabControl.Items.Add( ti1 );
		}
		
		//开始编译处理
		void Start( bool isShowForm )
		{
			listBox.Items.Clear();
		}
		
		//显示错误信息
		void ShowError()
		{
			listBox.Items.Clear();
			string[] r = ET.Show().Split( '\n' );
			for( int i = 0; i < r.Length; ++i ) {
				listBox.Items.Add( r[i] );
			}
		}
		
		//隐藏错误信息
		void HiddError()
		{
			//T.ErrorBox.Visible = false;
			
			tabControl.Height = 23;
		}
		
		//显示下载进度条
		void ShowProgressStep( int vNumber, int vIndex )
		{
			if( vIndex >= vNumber - 1 ) {
				vIndex = 0;
			}
			progressBar.Value = vIndex * 100 / vNumber;	
		}
		
		//显示下载信息
		void ShowISPStep( string Mes )
		{
			
		}
		
		void CheckClick(object sender, EventArgs e)
		{
			if( !SaveFile() ) {
				return;
			}
			//添加编译源码类
			CCode ccode = new CCode( CurrentFileName );
			ccode.isSystemFile = false;
			ccode.isNew = false;
			ccode.SetCode( textEditor.Text );
			G.ccode = ccode;
			
			ControlCenter.Check( true, false );
		}
		
		void CompileClick(object sender, EventArgs e)
		{
			if( !SaveFile() ) {
				return;
			}
			//添加编译源码类
			CCode ccode = new CCode( CurrentFileName );
			ccode.isSystemFile = false;
			ccode.isNew = false;
			ccode.SetCode( textEditor.Text );
			G.ccode = ccode;
			
			ControlCenter.Compile( true, false );
		}
		
		void DownloadClick(object sender, EventArgs e)
		{
			if( !SaveFile() ) {
				return;
			}
			//添加编译源码类
			CCode ccode = new CCode( CurrentFileName );
			ccode.isSystemFile = false;
			ccode.isNew = false;
			ccode.SetCode( textEditor.Text );
			G.ccode = ccode;
			
			ControlCenter.Auto( true, false );
		}
		
		void ErrorList_SelectionChanged(object sender, EventArgs e)
		{
			if( ET.isErrors() && listBox.SelectedIndex != -1 ) {
				string Target = listBox.SelectedItem.ToString();
				MessageBox.Show( Target );
			}
		}
		
		void ti0_MouseDown(object sender, EventArgs e)
		{
			tabControl.Height = 200;
		}
		
		//设置显示信息
		public void AddCheckMessage( int Step )
		{
			tabControl.Height = 250;
			
			if( Step == 0 ) {
				listBox.Items.Clear();
			}
			string Message = Compiler.GetCheckDescribe( Step );
			listBox.Items.Add(Message);
			System.Windows.Forms.Application.DoEvents();
		}
		
		//设置显示信息
		public void AddCompileMessage( int Step )
		{
			tabControl.Height = 250;
			
			if( Step == 0 ) {
				listBox.Items.Clear();
			}
			string Message = Compiler.GetDescribe( Step );
			listBox.Items.Add(Message);
			System.Windows.Forms.Application.DoEvents();
		}
		
		//===============================================================
		
		void WindowsClosing(object sender, System.ComponentModel.CancelEventArgs e)
		{
			if( isChanged ) {
				MessageBoxResult mr = MessageBox.Show( "文件已经被修改, 需要保存吗?", "文件保存提示", MessageBoxButton.YesNoCancel );
				if( mr == MessageBoxResult.Cancel ) {
					e.Cancel = true;
					return;
				}
				if( mr == MessageBoxResult.Yes ) {
					if( !SaveFile() ) {
						e.Cancel = true;
						return;
					}
				}
				if( mr == MessageBoxResult.No ) {
					//...
				}
			}
			A.Close();
		}
	}
}







